package com.bzkj.msfx.service.impl;

import com.bzkj.common.annotation.DataSource;
import com.bzkj.common.core.domain.AjaxResult;
import com.bzkj.common.core.page.TableDataInfo;
import com.bzkj.common.enums.DataSourceType;
import com.bzkj.common.utils.file.FileUploadUtils;
import com.bzkj.common.utils.file.MimeTypeUtils;
import com.bzkj.msfx.domain.MsfxDrugInfo;
import com.bzkj.msfx.mapper.MsfxDrugInfoMapper;
import com.bzkj.msfx.service.MsfxDrugInfoService;
import com.bzkj.msfx.utils.FusionHttpUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.annotation.Resource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * (DrugInfo)表服务实现类
 *
 * @author chj
 * @since 2023-10-10 09:42:07
 */
@Service
public class MsfxDrugInfoServiceImpl implements MsfxDrugInfoService {

    @Resource
    private MsfxDrugInfoMapper drugInfoDao;

    @Resource
    private FusionHttpUtils fusionHttpUtils;

    @Value("${bzkj.profile}")
    private String filePath;

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    @DataSource(DataSourceType.SLAVE)
    public MsfxDrugInfo queryById(Long id) {
        return this.drugInfoDao.queryById(id);
    }


    /**
     * 分页查询
     *
     * @param drugInfo 筛选条件
     * @return 查询结果
     */
    @Override
    public TableDataInfo queryByPage(MsfxDrugInfo drugInfo) {

        return fusionHttpUtils.getTableDataInfo("/basic/drugInfo/list", drugInfo);
    }

    /**
     * 药品信息文件上传与解析
     *
     * @param file 上传文件
     * @return 文件上传结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult parsingFile(MultipartFile file) {
        try {
            // 先向融合系统进行文件上传
            AjaxResult ajaxResult = fusionHttpUtils.sendFiles(file, "/basic/drugInfo/insert");
            // 如果融合系统返回成功，则进行wms系统进行药品信息新增
            if (ajaxResult.isSuccess()) {
                String fileName = FileUploadUtils.upload(filePath, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, false);
                String realFileUrl = filePath + "/" + fileName;
                String extension = FileUploadUtils.getExtension(file);
                Map<String, Object> resMap = new HashMap<>();
                if ("xml".equalsIgnoreCase(extension)) {
                    //解析码上放心药品信息文件
                    resMap = parsingXml(realFileUrl, true);
                }
                int sum = 0;
                if ((boolean) resMap.get("status")) {
                    @SuppressWarnings("unchecked")
                    List<MsfxDrugInfo> drugInfos = (List<MsfxDrugInfo>) resMap.get("data");
                    for (MsfxDrugInfo drugInfo : drugInfos) {
                        // 如果工厂ID不为空，则根据工厂ID查询部门ID（证明是企业管理员再导入数据，需要将导入的数据按照工厂ID进行分组）
                        sum += drugInfoDao.insert(drugInfo);

                    }
                    return AjaxResult.success("文件解析成功，共导入" + sum + "条数据");
                } else {
                    throw new RuntimeException("文件解析失败");
                }
            }
            return ajaxResult;
        } catch (Exception e) {
            // 使用日志框架替代 printStackTrace()
            e.printStackTrace();

//            log.warn("码上放心往来单位文件处理失败，原因：{}", e.getMessage(), e);
            throw new RuntimeException("码上放心药品信息文件处理失败，原因：" + e.getMessage());
        }
    }

    /**
     * 根据typeNo查询药品信息
     *
     * @param typeNo 药品子类编码
     * @return 查询结果
     */
    @Override
    public AjaxResult queryByNo(String typeNo) {
        try {
            return fusionHttpUtils.sendGetRestFulApi("/basic/drugInfo/" + typeNo);
        } catch (Exception e) {
            return AjaxResult.error("码上放心药品信息查询处理失败，原因：" + e.getMessage());
        }
    }

    /**
     * 解析药品信息文件
     *
     * @param url 药品信息文件路径
     * @param del 是否删除文件
     * @return 文件解析结果
     */
    public static Map<String, Object> parsingXml(String url, Boolean del) {
        ArrayList<MsfxDrugInfo> drugInfos = new ArrayList<>();
        Map<String, Object> resMap = new HashMap<>();
        try {

            File xmlFile = new File(url);

            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            Document doc = dBuilder.parse(xmlFile);
            doc.getDocumentElement().normalize();

            NodeList productList = doc.getElementsByTagName("product");
            for (int i = 0; i < productList.getLength(); i++) {
                Element productElement = (Element) productList.item(i);
                String productName = productElement.getAttribute("productName");
                String productCode = productElement.getAttribute("productCode");

                NodeList subTypeList = productElement.getElementsByTagName("subType");
                for (int j = 0; j < subTypeList.getLength(); j++) {
                    Element subTypeElement = (Element) subTypeList.item(j);
                    String typeNo = subTypeElement.getAttribute("typeNo");
                    String authorizedNo = subTypeElement.getAttribute("authorizedNo");
                    String type = subTypeElement.getAttribute("type");
                    String spec = subTypeElement.getAttribute("spec");
                    String packagespec = subTypeElement.getAttribute("packageSpec");
                    String packunit = subTypeElement.getAttribute("packUnit");
                    String physicdetailtype = subTypeElement.getAttribute("physicDetailType");
                    NodeList resCodeList = subTypeElement.getElementsByTagName("resCode");
                    for (int l = 0; l < resCodeList.getLength(); l++) {
                        Element resCodeElement1 = (Element) resCodeList.item(l);
                        String codeVersion = resCodeElement1.getAttribute("codeVersion");
                        String codeLevel = resCodeElement1.getAttribute("codeLevel");
                        String pkgRatio = resCodeElement1.getAttribute("pkgRatio");
                        String resCodeValue = resCodeElement1.getTextContent();

                        MsfxDrugInfo drugInfo = new MsfxDrugInfo();
                        drugInfo.setProductName(productName);
                        drugInfo.setProductCode(productCode);
                        drugInfo.setTypeNo(typeNo);
                        drugInfo.setAuthorizedNo(authorizedNo);
                        drugInfo.setCodeVersion(codeVersion);
                        drugInfo.setCodeLevel(codeLevel);
                        drugInfo.setPkgRatio(pkgRatio);
                        drugInfo.setResCode(resCodeValue);
                        drugInfo.setType(type);
                        drugInfo.setSpec(spec);
                        drugInfo.setPackageSpec(packagespec);
                        drugInfo.setPackUnit(packunit);
                        drugInfo.setPhysicDetailType(physicdetailtype);
                        drugInfo.setDrugCode(codeVersion + resCodeValue);
                        drugInfos.add(drugInfo);
                    }
                    //判断文件是否删除
                    if (del) {
                        new File(url).delete();
                    }
                    resMap.put("status", true);
                    resMap.put("msg", "文件读取成功");
                    resMap.put("data", drugInfos);
                }
            }
        } catch (ParserConfigurationException | IOException | SAXException e) {
            // 处理异常，可以根据实际需求进行处理
            e.printStackTrace();
            resMap.put("status", false);
            resMap.put("msg", "文件读取失败！");
        }
        return resMap;
    }

    /**
     * 新增数据(单个新增药品信息数据，注：保留功能）
     *
     * @param drugInfo 实例对象
     * @return 实例对象
     */
    @Override
    @DataSource(DataSourceType.SLAVE)
    public MsfxDrugInfo insert(MsfxDrugInfo drugInfo, Long deptId) {
        this.drugInfoDao.insert(drugInfo);
        return drugInfo;
    }

    /**
     * 修改码上放心药品数据（保留功能）
     *
     * @param drugInfo 实例对象
     * @return 实例对象
     */
    @Override
    @DataSource(DataSourceType.SLAVE)
    public MsfxDrugInfo update(MsfxDrugInfo drugInfo) {
        this.drugInfoDao.update(drugInfo);
        return this.queryById(drugInfo.getId());
    }

    /**
     * 通过主键删除数据(保留功能）
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    @DataSource(DataSourceType.SLAVE)
    public boolean deleteById(Long id) {
        return this.drugInfoDao.deleteById(id) > 0;
    }
}
